#include "DXUT.h"
#include <PrecompiledHeader.h>
#include "Shader.h"
#include "VertexDecl.h"
#include "Buffer.h"
#include "Pipeline.h"
using namespace d3d11;

Pipeline::Pipeline()
:m_pVertexShader(NULL),m_pPixelShader(NULL),m_pVertexLayout(NULL),m_pVertexDecl(NULL)
{
	m_pD3DDevice9 = DXUTGetD3D9Device();
	if (m_pD3DDevice11 = DXUTGetD3D11Device())
	{
		m_pVertexDecl = new VertexDecl();
	}
}

Pipeline::~Pipeline()
{	
	SAFE_RELEASE(m_pVertexLayout);
	SAFE_DELETE(m_pVertexShader);
	SAFE_DELETE(m_pPixelShader);
	SAFE_DELETE(m_pVertexDecl);		
}

void Pipeline::CreateVertexShader(LPCWSTR vertexShaderPath, LPCSTR entryFunction)
{
	CASSERT(m_pVertexShader == NULL, "Vertex shader has already been created.");

	m_pVertexShader = new Shader();

	if (m_pD3DDevice9)
	{
		m_pVertexShader->ConstructShader(Shader::VERTEX9, vertexShaderPath, entryFunction);
	}
	else
	{
		m_pVertexShader->ConstructShader(Shader::VERTEX11, vertexShaderPath, entryFunction);
	}
}
void Pipeline::PushVertexData(VertexData::DataType type, DXGI_FORMAT format, uint size)
{
	if (m_pD3DDevice9)
	{
		// DirectX 9
	}
	else
	{
		m_pVertexDecl->PushVertexData(type, format, size);
	}
}

void Pipeline::CreateInputLayout()
{
	if (m_pD3DDevice9)
	{
		// DirectX 9
	}
	else
	{
		CASSERT(m_pVertexLayout == NULL, "Vertex layout is already set.");
		CASSERT(m_pVertexShader != NULL, "Vertex shader must be loaded to create an input layout.");
		CASSERT(m_pVertexDecl->getNumElements() > 0, "Vertex Declaration must have at least one element.");

		// DirectX 11
		HRESULT hr = S_OK;

		m_pVertexDecl->ConstructElementLayout();

		if(FAILED(hr = m_pD3DDevice11->CreateInputLayout(
			m_pVertexDecl->getElementLayout(), 
			m_pVertexDecl->getNumElements(), 
			m_pVertexShader->getBlob()->GetBufferPointer(), 
			m_pVertexShader->getBlob()->GetBufferSize(), 
			&m_pVertexLayout)))
		{
			CASSERT(m_pVertexLayout != NULL, "CreateInputLayout failed.");
		}	
	}
}

void Pipeline::CreatePixelShader(LPCWSTR pixelShaderPath, LPCSTR entryFunction)
{
	CASSERT(m_pPixelShader == NULL, "Pixel shader has already been created.");

	m_pPixelShader = new Shader();
	
	if (m_pD3DDevice9)
	{
		m_pPixelShader->ConstructPixelShader9(pixelShaderPath);
	}
	else
	{
		m_pPixelShader->ConstructShader(Shader::PIXEL11, pixelShaderPath, entryFunction);
	}
}

void Pipeline::EnablePipeline()
{
	if (m_pD3DDevice9)
	{
		// Use directX 9
		// set vertex shader
		if (m_pVertexShader)
		{
			m_pD3DDevice9->SetVertexShader(m_pVertexShader->getVertexShader9());
		}

		// set pixel shader
		if (m_pPixelShader)
		{
			m_pD3DDevice9->SetPixelShader(m_pPixelShader->getPixelShader9());
		}
	}
	else
	{
		CASSERT(m_pVertexShader != NULL, "Vertex shader isn't set, Pipeline cannot be enabled.");
		CASSERT(m_pPixelShader != NULL, "Pixel shader isn't set, Pipeline cannot be enabled.");
		CASSERT(m_pVertexLayout != NULL, "Vertex layout isn't set, Pipeline cannot be enabled.");
		
		// set the vertex shader
		DXUTGetD3D11DeviceContext()->VSSetShader(m_pVertexShader->getVertexShader11(), NULL, 0);

		// TODO: set the constant buffers

		// set the vertex layout
		DXUTGetD3D11DeviceContext()->IASetInputLayout( m_pVertexLayout );

		// TODO: set the constant buffers

		// set the pixel shader
		DXUTGetD3D11DeviceContext()->PSSetShader( m_pPixelShader->getPixelShader11(), NULL, 0 );
	}
}
